
#include "EesTraderApi.h"


#include "string.h"
#include "Config.h"
#include "Lock.h"
#include "mystruct.h"
#include <map>
#include <set>
#include <vector>
#include <string>
#include "qtapi.h"
#include "Event.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mylogger.h"


EESTraderApi* CreateEESTraderApi(void) ; 


class RemTradeSpi;

class RemClient;

#define MAX_ORDERS_ 100
#define TRADES_COUNT_ 100
#define MSG_FINSTRUMENT_SATATUS2_ 2



class BaseInsPosition{
public:
	bool	m_bIsSHFE;
	bool	m_bIsCZCE;
	char	m_cIns[32];
	char	m_cTradingDay[16];

	int		LongVolume;
	int		LongTodayVolume;
	int		LongTotalClosable;
	int		LongTodayClosable;
	double	LongOpenAmmount;
	double	LongPositionAmmount;
	double	LongCloseProfit;
	double	LongPositionProfit;
	int		ShortVolume;
	int		ShortTodayVolume;
	int		ShortTotalClosable;
	int		ShortTodayClosable;
	double	ShortOpenAmmount;
	double	ShortPositionAmmount;
	double	ShortCloseProfit;
	double	ShortPositionProfit;

	int		m_nMultiply;

public:
	BaseInsPosition(){
		LongVolume = 0;
		LongTodayVolume = 0;
		LongTotalClosable = 0;
		LongTodayClosable = 0;
		LongOpenAmmount = 0;
		LongPositionAmmount = 0;
		LongCloseProfit = 0;

		ShortVolume = 0;
		ShortTodayVolume = 0;
		ShortTotalClosable = 0;
		ShortTodayClosable = 0;
		ShortOpenAmmount = 0;
		ShortPositionAmmount = 0;
		ShortCloseProfit = 0;
		m_nMultiply = 1;

		LongCloseProfit = 0;
		LongPositionProfit = 0;

		ShortCloseProfit = 0;
		ShortPositionProfit = 0;
	}

	virtual ~BaseInsPosition(){

	}

	virtual void Lock()=0;

	virtual void Unlock()=0;
};








class RemInsPosition:public BaseInsPosition{
public:
	double OpenCommissionRateByVolume;
	double OpenCommissionRateByMoney;
	double CloseCommissionRateByMoney;
	double CloseCommissionRateByVolume;
	double CloseTodayCommissionRateByMoney;
	double CloseTodayCommissionRateByVolume;

	double Commission;
	double ClosedAmmount;
	double ClosedTodayAmmount;
	double OpenedAmmount;

	int    OpenedVolume;
	int    ClosedVolume;
	int    ClosedTodayVolume;

	double LongMarginRateByMoney;
	double ShortMarginRateByMoney;

	double LongMarginByVolume;
	double ShortMarginByVolume;

private:	
	CLock							m_Lock;
	list<PositionDetailField*>		m_lTdLong;
	list<PositionDetailField*>		m_lYdLong;

	list<PositionDetailField*>		m_lTdShort;
	list<PositionDetailField*>		m_lYdShort;

private:

	void AddPositionDetail(list<PositionDetailField*>* pList,int nVolume,double fOpenPrice,double fPositionPrice,const char *pszOpenDate,const char *pszTradeID,bool bNewOpen=false);

	void CloseLongPositionDetail(list<PositionDetailField*>* pList,EES_OrderExecutionField* pField);

	void CloseShortPositionDetail(list<PositionDetailField*>* pList,EES_OrderExecutionField* pField);

public:
	RemInsPosition(const char *pszIns,bool bIsSHFE,const char *pszTradingDay,int nMultiply);

	virtual ~RemInsPosition();

	inline void UpdatePosition(EES_OrderExecutionField* pField);

	inline void AddPositionDetail(EES_AccountPosition* pPosDetail);

	inline void AddPositionDetail(EES_OrderExecutionField* pField,bool bIsLong);

	inline void ClosePositionDetail(EES_OrderExecutionField* pField);

	inline void GetLongPos(int& nTotal,int& nClosable,int& nTodayClosable){
		nTotal = LongVolume;
		nClosable = LongTotalClosable;
		nTodayClosable = LongTodayClosable;
	}

	inline void GetLongPos(int& nTotal,int& nClosable,int& nTodayClosable,double& fAvgOpenPrice){
		nTotal = LongVolume;
		nClosable = LongTotalClosable;
		nTodayClosable = LongTodayClosable;
		if(LongVolume>0){
			fAvgOpenPrice = LongOpenAmmount/LongVolume;
		}else{
			fAvgOpenPrice = 0;
		}
	}

	inline void GetShortPos(int& nTotal,int& nClosable,int& nTodayClosable){
		nTotal = ShortVolume;
		nClosable = ShortTotalClosable;
		nTodayClosable = ShortTodayClosable;
	}

	inline void GetShortPos(int& nTotal,int& nClosable,int& nTodayClosable,double& fAvgOpenPrice){
		nTotal = ShortVolume;
		nClosable = ShortTotalClosable;
		nTodayClosable = ShortTodayClosable;
		if(ShortVolume>0){
			fAvgOpenPrice = ShortOpenAmmount/ShortVolume;
		}else{
			fAvgOpenPrice = 0;
		}

	}

	inline void GetPos(int& nLong,int& nLongClosable,int nLongTodayClosable,int& nShort,int& nShortClosable,int nShortTodayClosable){
		nLong = LongVolume;
		nLongClosable = LongTotalClosable;
		nLongTodayClosable = LongTodayClosable;

		nShort = ShortVolume;
		nShortClosable = ShortTotalClosable;
		nShortTodayClosable = ShortTodayClosable;
	}

	//todo 
	void CalProfit(){
		

	}

	//todo
	void CalCommission(){
		
	}
	
	void Lock(){
		m_Lock.Lock();
	}

	void Unlock(){
		m_Lock.Unlock();
	}
};


struct RemOrderField: public OrderField{
	char UserOrderLocalID[21];
	char BrokerID[8];
	char UserID[12];
	char InvestorID[12];

	bool Frozened;
	bool Restored;
	int  TradedVolume;

	time_t  CancelTime;
	bool	SysReturned;
	bool	CtpReturned;
	int 	Stage1;
	int 	Stage2;
	int 	Stage3;
	int 	Canceling;

	EES_EnterOrderField* pInputOrderField;

	RemOrderField(){
		memset(this,0,sizeof(RemOrderField));
	}
};


class RemTradeSpi : public EESTraderEvent{
public:
	//CThostFtdcBrokerTradingParamsField	m_Params;
	map<string,EES_SymbolField*>		m_Instruments;
	map<string,RemInsPosition*>			m_Positions;
	EES_AccountInfo	m_Account;
	CLock m_AcctLock;

	void* m_pFutureAccount;

	time_t  m_tLastTradeTime;
	int 	m_bOnline;
	CMyConfig2	m_Config;

//attributes;
private:
	bool					m_bInBg;
	int						m_nLastError;
	char					m_cLastError[256];
	char					m_cInitFile[256];
	int 					m_nSeconds;
	char 					m_cCurTime[12];


	time_t					m_tLastOrderTime;
	time_t					m_tLastQueryAcctTime;


	EESTraderApi*		m_pTradeApi;

	CSpinLock				m_PosLock;
	CSpinLock				m_OrderLock;

	int						m_nOrdersCount;
	int						m_nOrdersCreated;
	RemOrderField*			m_pOrders[MAX_ORDERS_+1];
	map<string,RemOrderField*>	m_OrdersByLocalID;
	map<string,RemOrderField*>	m_OrdersBySysID;

	int						m_nNextTrade;
	TradeField				m_TradeFields[TRADES_COUNT_];

	map<string,string>		m_LatestTradeID;
	set<string>				m_TradeIDs;	

	map<string,list<EES_OrderExecutionField*>*>		m_CachedTrades;

	CLock							m_OALock;
	map<int,int>					m_FailedOA;

	//market data cache;
	CLock			m_MdLock;
	map<string,MarketDataField*> m_LastMarketData;

	//log buffers;
	//LogMsg	m_LogMsg[256];
	int		m_nNextMsg;
	CLock	m_lockMsg;

	char m_cInvestorID[32];
	int		m_nFrontID;
	int		m_nSessionID;

	CEvent m_hQueryFinished;
	list<RemClient*>		m_Clients;
	map<string, IPolicy*> policies;   // <OrderRef, Policy>
	map<string, RemOrderField*> RemOrderFields; // <OrderRef, RemOrderField>
	CLock m_ClientsLock;

	CSpinLock   m_coclock;
	map<string,int>  m_CancelOrdersCount;

	FILE * m_pfLog;
	int    m_nSeed;

	// my variable
	bool   m_connected;
	bool b_authenticated;
	bool b_position;
    bool b_instruments;
	//新加3个参数
//std::string pszAppID;
//std::string pszAuthCode;
//std::string pszProductInfo;
//新增持仓
    std::unordered_map<std::string, EES_AccountPosition> long_pos_map_;
    std::unordered_map<std::string, EES_AccountPosition> short_pos_map_;
//品种信息
    std::unordered_map<std::string, EES_SymbolField> future_instruments_;


	vector<IPolicy*> v_policy;

private:

	void CacheTrade(EES_OrderExecutionField* pField);

	void FlushCachedTrade(RemOrderField* pOrder);

	RemOrderField* GetOrderByBrokerOID(const char* pszBrokerOrderID);

	double GetLastPrice(const char *psz){
		double fPrice=0;
		m_MdLock.Lock();
		map<string,MarketDataField*>::iterator it = m_LastMarketData.find(psz);
		if(it != m_LastMarketData.end()){
			MarketDataField* pData = it->second;
			fPrice = pData->LastPrice;
		}
		m_MdLock.Unlock();
		return fPrice;
	}

	double GetAveragePrice(const char *psz){
		double fPrice=0;
		m_MdLock.Lock();
		map<string,MarketDataField*>::iterator it = m_LastMarketData.find(psz);
		if(it != m_LastMarketData.end()){
			MarketDataField* pData = it->second;
			fPrice = pData->AveragePrice;
		}
		m_MdLock.Unlock();
		return fPrice;
	}

	double GetPreSettlementPrice(const char *psz){
		double fPrice=0;
		m_MdLock.Lock();
		map<string,MarketDataField*>::iterator it = m_LastMarketData.find(psz);
		if(it != m_LastMarketData.end()){
			MarketDataField* pData = it->second;
			fPrice = pData->PreSettlementPrice;
		}
		m_MdLock.Unlock();
		return fPrice;
	}

	//query instruments;
	int QueryAccount();
	
	//query instruments;
	//int QueryInstruments();

	//query detail positions;
	//int QueryDetailPositions();

	int ReqClientLogin(const char *pszAuthCode);

	int ReqUserLogin();

	//穿透式监管
	int ReqAuthenticate();
	//void OnRspDSUserCertification(CUstpFtdcDSUserCertRspDataField *pDSUserCertRspData, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
	void OnRspAuthenticate(CThostFtdcRspAuthenticateField *pRspAuthenticateField, CThostFtdcRspInfoField *pRspInfo,
                              int nRequestID, bool bIsLast);
							  
//    void OnRspQryInstrument(CUstpFtdcRspInstrumentField *pRspInstrument, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
void OnRspQryInstrument(CThostFtdcInstrumentField *pInstrument, CThostFtdcRspInfoField *pRspInfo, int nRequestID,
                               bool bIsLast);
							   
//    void OnRspQryInvestorPosition(CUstpFtdcRspInvestorPositionField *pRspInvestorPosition, CUstpFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
void OnRspQryInvestorPosition(CThostFtdcInvestorPositionField *pInvestorPosition,
                                                   CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
												   
void OnRspSettlementInfoConfirm(CThostFtdcSettlementInfoConfirmField *pSettlementInfoConfirm,
                                                     CThostFtdcRspInfoField *pRspInfo, int nRequestID, bool bIsLast);
    bool req_position();
	bool req_settlement_confirm();
    bool req_qry_instrument();


	void ReqUserInvestor();

	//confirm settlement;
	//int Confirm();

	//update local position cache;
	inline void UpdatePosition(EES_OrderExecutionField *pField);

	//check whether an instrument is of SHFE exchange;
	inline bool IsSHFE(const char *pszIns);

	//frozen position when a close order is sent;
	void FrozenPosition(RemOrderField* pOrder,const char *pszCode,char cBuySell,char cClose,int nVolume);

	//unfrozend position when a close order is canceled;
	void UnfrozenPosition(RemOrderField* pOrder);

	//get next trade field;
	TradeField* GetNextTradeField();

public:
	RemTradeSpi(const char *pszInitFile=nullptr);
	virtual ~RemTradeSpi();

	void AddPolicy(IPolicy* newPolicy)
	{
		v_policy.push_back(newPolicy);
	}

	void DeletePolicy(IPolicy* oldPolicy)
	{
		vector<IPolicy*>::iterator iter = v_policy.begin();
		for (; iter != v_policy.end(); iter++)
		{
			if (*iter == oldPolicy)
				break;
		}

		v_policy.erase(iter);
	}

	int GetCancelOrdersCount(const char* pszIns){
		int nCount=0;
		m_coclock.Lock();
		map<string,int>::iterator it = m_CancelOrdersCount.find(pszIns);
		if(it != m_CancelOrdersCount.end()){
			nCount = it->second;
		}
		m_coclock.Unlock();

		return nCount;
	}

	void IncCancelOrdersCount(const char* pszIns){
		m_coclock.Lock();
		map<string,int>::iterator it = m_CancelOrdersCount.find(pszIns);
		if(it != m_CancelOrdersCount.end()){
			it->second++;
		}else{
			m_CancelOrdersCount.insert(pair<string,int>(pszIns,1));
		}
		m_coclock.Unlock();
	}
	void PostLogMessage(const char *pszLog,int nLevel);
	void OpenLog(){
		char cFileName[256];
		char cDate[16];

		time_t t;
		time(&t);

		struct tm* pTm = localtime(&t);
		strftime(cDate,15,"%Y%m%d",pTm);

		strcpy(cFileName,"./logs/");
		strcat(cFileName,m_Config.GetUser());
		strcat(cFileName,"_");
		strcat(cFileName,cDate);
		strcat(cFileName,".log");

		m_pfLog = fopen(cFileName,"at+");
	}


	/**
	 *login to trade;
	 */
	virtual int Login(const char* UserID,const char* Password,char* ErrorMsg,int* ErrorID);

	virtual int Logout(){
		if(m_pTradeApi){

			int nTried = 0;
			//int retCode = m_pTradeApi->ReqUserLogout(&reqUserLogout, 2);
            int retCode = m_pTradeApi->DisConnServer();

			while(retCode<0 && nTried++ <4){
                std::cout << "in Logout while " << std::endl;
                sleep(1);
				 retCode = m_pTradeApi->DisConnServer();
			}
		}
		return 1;
	}

	virtual IFutureTrader* CreateTrader(IPolicy* pPolicy,char cHedgeFlag='1',bool IsSHFE=false);

	void Stop(){
		if(m_pTradeApi != NULL){
			//m_pTradeApi->RegisterSpi(NULL);
            m_pTradeApi->DisConnServer();
			m_pTradeApi = NULL;
		}
	}

	virtual void Release(){
		delete this;
	}

	int GetLastErrorID();

	char* GetLastErrorMsg();

	void Log(const char *pszLog,int nLevel,long ThreadID);

	void CloseLog();

	virtual void Debug(const char *pszLog);

	virtual void Info(const char *pszLog);

	virtual void Error(const char *pszLog);

	//LogMsg* GetLogMsg();

	virtual void OnFutureMarketData(MarketDataField* pData);




	const char * GetInitFile();


	const char * GetTradingDay(){
		return this->m_Config.GetTradingDay();
	}
	//create emtpy new orders for late use;
	void CreateEmptyOrders();

	bool IsFinished(RemOrderField* pOrder);

	RemOrderField* GetOrderByID(int nOrderID);

	RemOrderField* GetNewOrder();

	RemOrderField* GetNewOrderNoLock();

	RemOrderField* GetNewOrderByID(int nOrderID);

	int CheckMyOrderID(const char * psz);

	//login to the md server;
	int Login(const char *pszUserID,const char *pszPassword);

	// set TimeCondition = '1' only for FAK
	// set TimeCondition = '1' & VolCondition = '3' for FOK
	inline RemOrderField* Buy(const char *pszCode,int nVolume,double fPrice,IPolicy *pOrderListener=NULL,char HedgeFlag=EES_HedgeFlag_Speculation,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		return PlaceOrder(pszCode,EES_PosiDirection_long,EES_SideType_open_long,nVolume,fPrice,pOrderListener,HedgeFlag,cPriceType,cTimeCondition,cVolCondition,nMinVolume);
	}

	inline RemOrderField* Short(const char *pszCode,int nVolume,double fPrice,IPolicy *pOrderListener=NULL,char HedgeFlag=EES_HedgeFlag_Speculation,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		return PlaceOrder(pszCode,EES_PosiDirection_short,EES_SideType_open_long,nVolume,fPrice,pOrderListener,HedgeFlag,cPriceType,cTimeCondition,cVolCondition,nMinVolume);
	}

	inline RemOrderField* Sell(const char *pszCode,int nVolume,double fPrice,bool bIsSHFE=false,IPolicy *pOrderListener=NULL,char HedgeFlag=EES_HedgeFlag_Speculation,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		return PlaceOrder(pszCode,EES_PosiDirection_short,EES_SideType_close_short,nVolume,fPrice,pOrderListener,HedgeFlag,cPriceType,cTimeCondition,cVolCondition,nMinVolume);
	}

	inline RemOrderField* Cover(const char *pszCode,int nVolume,double fPrice,bool bIsSHFE=false,IPolicy *pOrderListener=NULL,char HedgeFlag=EES_HedgeFlag_Speculation,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		return PlaceOrder(pszCode,EES_PosiDirection_long,EES_SideType_close_short,nVolume,fPrice,pOrderListener,HedgeFlag,cPriceType,cTimeCondition,cVolCondition,nMinVolume);
	}

	inline RemOrderField* PlaceOrder(const char *pszCode,char cBuySell,char cOpenClose,int nVolume,double fPrice,IPolicy *pPolicy=NULL,char HedgeFlag=EES_HedgeFlag_Speculation,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		int nRetCode;


		EES_EnterOrderField* pInputOrderField =new EES_EnterOrderField();

		strcpy(pInputOrderField->m_Account, m_Config.GetInvestorID());
		strcpy(pInputOrderField->m_Symbol, pszCode);

        m_OrderLock.Lock();

		if(b_instruments) {
            auto iter = future_instruments_.find(std::string(pszCode));
            if (iter != future_instruments_.end()){
                pInputOrderField->m_Exchange = iter->second.m_ExchangeID;
            }else{
                //do nothing, waiting for  OnRspOrderInsert
            }
		}else{
            //do nothing, waiting for  OnRspOrderInsert
		}


		pInputOrderField->m_Tif = EES_OrderTif_Day;
		pInputOrderField->m_HedgeFlag = HedgeFlag;
		pInputOrderField->m_Side = cBuySell;
		pInputOrderField->m_SecType = EES_SecType_fut;
		pInputOrderField->m_Price = fPrice;
		pInputOrderField->m_Qty = nVolume;
		pInputOrderField->m_ClientOrderToken = m_Config.GetAndIncMaxOrderRef();



		int nReqID = m_Config.GetNextRequestID();
		long orderRef = m_Config.GetAndIncMaxOrderRef();

		

		RemOrderField* pOrder = new RemOrderField();
		memset(pOrder, 0, sizeof(RemOrderField));
		strcpy(pOrder->BrokerID, pInputOrderField->m_Account);
		pOrder->Direction = pInputOrderField->m_Side;
		//to do
		//pOrder->ExchangeID = pInputOrderField->m_Exchange;
		pOrder->pInputOrderField = pInputOrderField;
		strcpy(pOrder->UserID, m_Config.GetUser());
		strcpy(pOrder->InvestorID, m_Config.GetInvestorID());
		strcpy(pOrder->InstrumentID, pszCode);
		pOrder->Volume = nVolume;
		strcpy(pOrder->UserOrderLocalID, std::to_string(pInputOrderField->m_ClientOrderToken).c_str());

		policies.insert(make_pair(std::to_string(pInputOrderField->m_ClientOrderToken), pPolicy));
		RemOrderFields.insert(make_pair(std::to_string(pInputOrderField->m_ClientOrderToken), pOrder));

		if (policies.find(std::to_string(pInputOrderField->m_ClientOrderToken)) != policies.end()
			&& RemOrderFields.find(std::to_string(pInputOrderField->m_ClientOrderToken)) != RemOrderFields.end())
		{
			SPDLOG_INFO("start to insert order. OrderID = {}" , pInputOrderField->m_ClientOrderToken);
		}

		nRetCode = m_pTradeApi->EnterOrder(pInputOrderField);
		SPDLOG_INFO("PlaceOrder nRetCode: {} ", (nRetCode == 0 ? "OK" : "Fail"));

		m_OrderLock.Unlock();

		return pOrder;

	}

	void GetLongPos(const char *pszIns,int& nTotal,int& nClosable,int& nTodayClosable);

	void GetShortPos(const char *pszIns,int& nTotal,int& nClosable,int& nTodayClosable);

	void GetLongPos(const char *pszIns,int& nTotal,int& nClosable,int& nTodayClosable,double& fAvgOpenPrice);

	void GetShortPos(const char *pszIns,int& nTotal,int& nClosable,int& nTodayClosable,double& fAvgOpenPrice);


	struct InstrumentField* GetInstrument(const char *pszInstrument);

	bool GetInstrument(FutureInstrumentField* pIns);

	void GetInstrument(const char* pszProductID,FutureInstrumentField** pIns,int* pCount);

	int GetMultiply(const char *pszInstrument);

	struct CThostFtdcRspInstrumentField* GetCtpInstrument(const char *pszInstrument);

	void SetBgTaskState(bool bInBg);

	void OnOneSecond();

	void RegisterTimer(RemOrderField* pField,int nAction,int nSecondsAfter,IPolicy* pListener);

	void GetLongAvgPrice(const char *pszIns,double& fAvgOpenPrice,double& fAvgPositionPrice);

	void GetShortAvgPrice(const char *pszIns,double& fAvgOpenPrice,double& fAvgPositionPrice);


// test
public:
    void test_order();

// rem spi----------------------------------------------------------------------------------------------------------------------------------
public:

	virtual void OnConnection(ERR_NO errNo, const char* pErrStr );

	/// 连接断开消息的回调
	
		/// \brief	服务器主动断开，会收到这个消息
		/// \param  ERR_NO errNo         连接成功能与否的消息
		/// \param  const char* pErrStr  错误信息
		/// \return void  
	
	virtual void OnDisConnection(ERR_NO errNo, const char* pErrStr );

	/// 登录消息的回调
	
		/// \param  pLogon                  登录成功或是失败的结构
		/// \return void 
	
	virtual void OnUserLogon(EES_LogonResponse* pLogon);

	/// 修改密码响应回调

	/// \param  nResult                  服务器响应的成功与否返回码
	/// \return void 

	virtual void OnRspChangePassword(EES_ChangePasswordResult nResult);

	/// 查询用户下面帐户的返回事件
	
		/// \param  pAccountInfo	        帐户的信息
		/// \param  bFinish	                如果没有传输完成，这个值是 false ，如果完成了，那个这个值为 true 
		/// \remark 如果碰到 bFinish == true，那么是传输结束，并且 pAccountInfo值无效。
		/// \return void 
	
	virtual void OnQueryUserAccount(EES_AccountInfo * pAccoutnInfo, bool bFinish);

	/// 查询帐户下面期货仓位信息的返回事件	
		/// \param  pAccount	                帐户ID 	
		/// \param  pAccoutnPosition	        帐户的仓位信息					   
		/// \param  nReqId		                发送请求消息时候的ID号。
		/// \param  bFinish	                    如果没有传输完成，这个值是false，如果完成了，那个这个值为 true 
		/// \remark 如果碰到 bFinish == true，那么是传输结束，并且 pAccountInfo值无效。
		/// \return void 	
	virtual void OnQueryAccountPosition(const char* pAccount, EES_AccountPosition* pAccoutnPosition, int nReqId, bool bFinish);	

	/// 查询帐户下面期权仓位信息的返回事件, 注意这个回调, 和上一个OnQueryAccountPosition, 会在一次QueryAccountPosition请求后, 分别返回, 先返回期货, 再返回期权, 即使没有期权仓位, 也会返回一条bFinish=true的记录
	/// \param  pAccount	                帐户ID 	
	/// \param  pAccoutnPosition	        帐户的仓位信息					   
	/// \param  nReqId		                发送请求消息时候的ID号。
	/// \param  bFinish	                    如果没有传输完成，这个值是false，如果完成了，那个这个值为 true 
	/// \remark 如果碰到 bFinish == true，那么是传输结束，并且 pAccountInfo值无效。
	/// \return void 	
	virtual void OnQueryAccountOptionPosition(const char* pAccount, EES_AccountOptionPosition* pAccoutnOptionPosition, int nReqId, bool bFinish) ;


	/// 查询帐户下面资金信息的返回事件
	
		/// \param  pAccount	                帐户ID 	
		/// \param  pAccoutnPosition	        帐户的仓位信息					   
		/// \param  nReqId		                发送请求消息时候的ID号
		/// \return void 
	
	virtual void OnQueryAccountBP(const char* pAccount, EES_AccountBP* pAccoutnPosition, int nReqId );	

	/// 查询合约列表的返回事件
	
		/// \param  pSymbol	                    合约信息   
		/// \param  bFinish	                    如果没有传输完成，这个值是 false，如果完成了，那个这个值为 true   
		/// \remark 如果碰到 bFinish == true，那么是传输结束，并且 pSymbol 值无效。
		/// \return void 
	
	virtual void OnQuerySymbol(EES_SymbolField* pSymbol, bool bFinish);

	/// 查询帐户交易保证金的返回事件
	
	    /// \param  pAccount                    帐户ID 
		/// \param  pSymbolMargin               帐户的保证金信息 
		/// \param  bFinish	                    如果没有传输完成，这个值是 false，如果完成，那个这个值为 true 
		/// \remark 如果碰到 bFinish == true，那么是传输结束，并且 pSymbolMargin 值无效。
		/// \return void 
	
	virtual void OnQueryAccountTradeMargin(const char* pAccount, EES_AccountMargin* pSymbolMargin, bool bFinish );

	/// 查询帐户交易费用的返回事件
	
		/// \param  pAccount                    帐户ID 
		/// \param  pSymbolFee	                帐户的费率信息	 
		/// \param  bFinish	                    如果没有传输完成，这个值是 false，如果完成了，那个这个值为 true    
		/// \remark 如果碰到 bFinish == true ，那么是传输结束，并且 pSymbolFee 值无效。
		/// \return void 
	
	virtual void OnQueryAccountTradeFee(const char* pAccount, EES_AccountFee* pSymbolFee, bool bFinish );

	/// 下单被柜台系统接受的事件
	
		/// \brief 表示这个订单已经被柜台系统正式的接受
		/// \param  pAccept	                    订单被接受以后的消息体
		/// \return void 
	
	virtual void OnOrderAccept(EES_OrderAcceptField* pAccept );


	/// 下单被市场接受的事件

	    /// \brief 表示这个订单已经被交易所正式的接受
	    /// \param  pAccept	                    订单被接受以后的消息体，里面包含了市场订单ID
	    /// \return void 
	virtual void OnOrderMarketAccept(EES_OrderMarketAcceptField* pAccept) ;


	///	下单被柜台系统拒绝的事件
	
		/// \brief	订单被柜台系统拒绝，可以查看语法检查或是风控检查。 
		/// \param  pReject	                    订单被接受以后的消息体
		/// \return void 
	
	virtual void OnOrderReject(EES_OrderRejectField* pReject );


	///	下单被市场拒绝的事件

	/// \brief	订单被市场拒绝，可以查看语法检查或是风控检查。 
	/// \param  pReject	                    订单被接受以后的消息体，里面包含了市场订单ID
	/// \return void 

	virtual void OnOrderMarketReject(EES_OrderMarketRejectField* pReject) ;


	///	订单成交的消息事件
	
		/// \brief	成交里面包括了订单市场ID，建议用这个ID查询对应的订单
		/// \param  pExec	                   订单被接受以后的消息体，里面包含了市场订单ID
		/// \return void 
	
	virtual void OnOrderExecution(EES_OrderExecutionField* pExec );

	///	订单成功撤销事件
	
		/// \brief	成交里面包括了订单市场ID，建议用这个ID查询对应的订单
		/// \param  pCxled		               订单被接受以后的消息体，里面包含了市场订单ID
		/// \return void 
	
	virtual void OnOrderCxled(EES_OrderCxled* pCxled );

	///	撤单被拒绝的消息事件
	
		/// \brief	一般会在发送撤单以后，收到这个消息，表示撤单被拒绝
		/// \param  pReject	                   撤单被拒绝消息体
		/// \return void 
	
	virtual void OnCxlOrderReject(EES_CxlOrderRej* pReject );

	///	查询订单的返回事件
	
		/// \brief	查询订单信息时候的回调，这里面也可能包含不是当前用户下的订单
		/// \param  pAccount                 帐户ID 
		/// \param  pQueryOrder	             查询订单的结构
		/// \param  bFinish	                 如果没有传输完成，这个值是 false，如果完成了，那个这个值为 true    
		/// \remark 如果碰到 bFinish == true，那么是传输结束，并且 pQueryOrder值无效。
		/// \return void 
	
	virtual void OnQueryTradeOrder(const char* pAccount, EES_QueryAccountOrder* pQueryOrder, bool bFinish  ); 

	///	查询订单的返回事件
	
		/// \brief	查询订单信息时候的回调，这里面也可能包含不是当前用户下的订单成交
		/// \param  pAccount                        帐户ID 
		/// \param  pQueryOrderExec	                查询订单成交的结构
		/// \param  bFinish	                        如果没有传输完成，这个值是false，如果完成了，那个这个值为 true    
		/// \remark 如果碰到 bFinish == true，那么是传输结束，并且pQueryOrderExec值无效。
		/// \return void 
	
	virtual void OnQueryTradeOrderExec(const char* pAccount, EES_QueryOrderExecution* pQueryOrderExec, bool bFinish  );

	///	接收外部订单的消息
	
		/// \brief	一般会在系统订单出错，进行人工调整的时候用到。
		/// \param  pPostOrder	                    查询订单成交的结构
		/// \return void 
	
	virtual void OnPostOrder(EES_PostOrder* pPostOrder );	

	///	接收外部订单成交的消息
	
		/// \brief	一般会在系统订单出错，进行人工调整的时候用到。
		/// \param  pPostOrderExecution	             查询订单成交的结构
		/// \return void 
	
	virtual void OnPostOrderExecution(EES_PostOrderExecution* pPostOrderExecution );

	///	查询交易所可用连接的响应

	/// \brief	每个当前系统支持的汇报一次，当bFinish= true时，表示所有交易所的响应都已到达，但本条消息本身不包含有用的信息。
	/// \param  pPostOrderExecution	             查询订单成交的结构
	/// \return void 
	virtual void OnQueryMarketSession(EES_ExchangeMarketSession* pMarketSession, bool bFinish) ;

	///	交易所连接状态变化报告，

	/// \brief	当交易所连接发生连接/断开时报告此状态
	/// \param  MarketSessionId: 交易所连接代码
	/// \param  ConnectionGood: true表示交易所连接正常，false表示交易所连接断开了。
	/// \return void 
	virtual void OnMarketSessionStatReport(EES_MarketSessionId MarketSessionId, bool ConnectionGood) ;

	///	合约状态变化报告

	/// \brief	当合约状态发生变化时报告
	/// \param  pSymbolStatus: 参见EES_SymbolStatus合约状态结构体定义
	/// \return void 
	virtual void OnSymbolStatusReport(EES_SymbolStatus* pSymbolStatus) ;


	///	合约状态查询响应

	/// \brief  响应合约状态查询请求
	/// \param  pSymbolStatus: 参见EES_SymbolStatus合约状态结构体定义
	/// \param	bFinish: 当为true时，表示查询所有结果返回。此时pSymbolStatus为空指针NULL
	/// \return void 
	virtual void OnQuerySymbolStatus(EES_SymbolStatus* pSymbolStatus, bool bFinish) ;

	/// 深度行情查询响应
	/// \param	pMarketMBLData: 参见EES_MarketMBLData深度行情结构体定义
	/// \param	bFinish: 当为true时，表示查询所有结果返回。此时pMarketMBLData内容中,仅m_RequestId有效
	/// \return void 
	//virtual void OnQueryMarketMBLData(EES_MarketMBLData* pMarketMBLData, bool bFinish) ;

};





class RemClient: public IFutureTrader{
private:
	bool			m_bIsSHFE;
	char			m_cHedgeType;
	RemTradeSpi*		m_pTradeSpi;

public:
	void* m_pFutureAcct;
	IPolicy*		m_pPolicy;

public:
	RemClient();;

	RemClient(IPolicy* pPolicy,RemTradeSpi* pTradeSpi,bool bIsSHFE,char cHedgeType);

	virtual ~RemClient(){ if (m_pTradeSpi != NULL) m_pTradeSpi->DeletePolicy(m_pPolicy); };

	IFutureAccount* GetFutureAccount(){
		return (IFutureAccount*)m_pFutureAcct;
	}
	RemOrderField*	Buy(const char *pszCode,int nVolume,double fPrice,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		return m_pTradeSpi->Buy(pszCode,nVolume,fPrice,m_pPolicy,m_cHedgeType,cPriceType,cTimeCondition,cVolCondition,nMinVolume);
	}

	virtual OrderField* Buy( const char* InstrumentID,int nVolume,double fPrice );

	RemOrderField*	Sell(const char *pszCode,int nVolume,double fPrice,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		return m_pTradeSpi->Sell(pszCode,nVolume,fPrice,m_bIsSHFE,m_pPolicy,m_cHedgeType,cPriceType,cTimeCondition,cVolCondition,nMinVolume);
	}

	virtual OrderField* Sell( const char* InstrumentID,int nVolume,double fPrice,int closeTd );

	RemOrderField*	Short(const char *pszCode,int nVolume,double fPrice,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		return m_pTradeSpi->Short(pszCode,nVolume,fPrice,m_pPolicy,m_cHedgeType,cPriceType,cTimeCondition,cVolCondition,nMinVolume);
	}

	virtual OrderField* Short( const char* InstrumentID,int nVolume,double fPrice );

	RemOrderField*	Cover(const char *pszCode,int nVolume,double fPrice,char cPriceType='2',char cTimeCondition='3',char cVolCondition='1',int nMinVolume=0){
		return m_pTradeSpi->Cover(pszCode,nVolume,fPrice,m_bIsSHFE,m_pPolicy,m_cHedgeType,cPriceType,cTimeCondition,cVolCondition,nMinVolume);
	}

	virtual OrderField* Cover( const char* InstrumentID,int nVolume,double fPrice,int closeTd );

	bool CancelOrder(OrderField* pOrder){
		//return m_pTradeSpi->CancelOrder((RemOrderField*)pOrder);
		return true;
	}

	virtual void GetTradingAccountInfo(double* PreBalance,double* CloseProfit,double* PositionProfit,double* Commission,double* Balance,double* Available){
		m_pTradeSpi->m_AcctLock.Lock();
		//*PreBalance =  m_pTradeSpi->m_Account.PreBalance;
		//*CloseProfit =  m_pTradeSpi->m_Account.CloseProfit;
		//*PositionProfit =  m_pTradeSpi->m_Account.PositionProfit;
		//*Commission =  m_pTradeSpi->m_Account.Commission;
		//*Balance =  m_pTradeSpi->m_Account.Balance;
		//*Available =  m_pTradeSpi->m_Account.Available;
		m_pTradeSpi->m_AcctLock.Unlock();
	}

	virtual void GetTradingAccountInfo2(double* PreBalance,double* CloseProfit,double* PositionProfit,double* Margin,double* Commission,double* Balance,double* Available){
		m_pTradeSpi->m_AcctLock.Lock();
		//*PreBalance =  m_pTradeSpi->m_Account.PreBalance;
		//*CloseProfit =  m_pTradeSpi->m_Account.CloseProfit;
		//*PositionProfit =  m_pTradeSpi->m_Account.PositionProfit;
		//*Margin = m_pTradeSpi->m_Account.ExchangeMargin;
		//*Commission =  m_pTradeSpi->m_Account.Commission;
		//*Balance =  m_pTradeSpi->m_Account.Balance;
		//*Available =  m_pTradeSpi->m_Account.Available;
		m_pTradeSpi->m_AcctLock.Unlock();
	}

	bool GetInstrument(FutureInstrumentField* pIns){
		return m_pTradeSpi->GetInstrument(pIns);
	}

	void GetInstrument(const char* pszProductID,FutureInstrumentField** ppIns,int* pCount){
		m_pTradeSpi->GetInstrument(pszProductID,ppIns,pCount);
	}

	void GetLongPos(const char *pszCode,int& nTotal,int& nClosable,int& nTodayClosable){
		m_pTradeSpi->GetLongPos(pszCode,nTotal,nClosable,nTodayClosable);
	}

	void GetShortPos(const char *pszCode,int& nTotal,int& nClosable,int& nTodayClosable){
		m_pTradeSpi->GetShortPos(pszCode,nTotal,nClosable,nTodayClosable);
	}

	void GetLongPos(const char *pszCode,int& nTotal,int& nClosable,int& nTodayClosable,double& fAvgOpenPrice){
		m_pTradeSpi->GetLongPos(pszCode,nTotal,nClosable,nTodayClosable,fAvgOpenPrice);
	}

	void GetShortPos(const char *pszCode,int& nTotal,int& nClosable,int& nTodayClosable,double& fAvgOpenPrice){
		m_pTradeSpi->GetShortPos(pszCode,nTotal,nClosable,nTodayClosable,fAvgOpenPrice);
	}


	void SendInstrumentStatus(CThostFtdcInstrumentStatusField* pStatus){
		if(m_pPolicy){
			CThostFtdcInstrumentStatusField* pNew = new CThostFtdcInstrumentStatusField();
			memcpy(pNew,pStatus,sizeof(CThostFtdcInstrumentStatusField));

			m_pPolicy->AddMsg(MSG_FINSTRUMENT_SATATUS2_,(void*)pNew);
		}
	}

	virtual const char * GetTradingDay(){
		return m_pTradeSpi->GetTradingDay();
	}

	void RegisterTimer(int nMilliSecondsAfter,int nAction,OrderField* pOrder);

	void Release();

	void LogError(const char* pszError);

	void LogInfo(const char *pszError);

	void LogDebug(const char *pszError);

	int GetCancelOrdersCount(const char *pszIns){
		return m_pTradeSpi->GetCancelOrdersCount(pszIns);
	}

	virtual void SetSHFE( bool bSHFE );





};







class REM_EES_AccountInfo:public IFutureAccount{
private:
	char m_cUser[64];
	char m_cPassword[64];

public:

	REM_EES_AccountInfo(){
		m_cUser[0]='\0';
		m_cPassword[0]='\0';
	}


	RemTradeSpi* m_pTradeSpi;

	virtual const char* GetUser();

	const char* GetBrokerID(){
		return m_pTradeSpi->m_Config.GetBroker();
	}

	virtual const char* GetPassword();

	/**
	 *login to trade;
	 */
	virtual int Login(const char* UserID,const char* Password,char* ErrorMsg,int* ErrorID);

	virtual int Logout();

	virtual IFutureTrader* CreateTrader(IPolicy* pPolicy,char cHedgeFlag='1',bool IsSHFE=false);

	virtual void Stop();

	virtual void Release();
};




